{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# schedule"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1: 25.04.2020 10:30:36\n",
      "1: 25.04.2020 10:30:36\n",
      "2: 25.04.2020 10:30:38\n",
      "1: 25.04.2020 10:30:38\n",
      "1: 25.04.2020 10:30:38\n",
      "2: 25.04.2020 10:30:38\n",
      "2: 25.04.2020 10:30:42\n",
      "1: 25.04.2020 10:30:42\n",
      "1: 25.04.2020 10:30:42\n",
      "2: 25.04.2020 10:30:42\n",
      "2: 25.04.2020 10:30:44\n",
      "1: 25.04.2020 10:30:44\n",
      "1: 25.04.2020 10:30:44\n",
      "2: 25.04.2020 10:30:44\n",
      "2: 25.04.2020 10:30:49\n",
      "2: 25.04.2020 10:30:49\n",
      "1: 25.04.2020 10:30:49\n",
      "1: 25.04.2020 10:30:49\n",
      "2: 25.04.2020 10:30:51\n",
      "2: 25.04.2020 10:30:51\n",
      "1: 25.04.2020 10:30:51\n",
      "1: 25.04.2020 10:30:51\n",
      "\n",
      " \n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "' '"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# -*- conding:utf-8 -*-\n",
    "import threading\n",
    "import time\n",
    "import sys\n",
    "\n",
    "import schedule\n",
    "\n",
    "\n",
    "def p1():\n",
    "    sys.stdout.write('1: ' + time.strftime(\"%d.%m.%Y %H:%M:%S\") + '\\n')\n",
    "\n",
    "\n",
    "def p2():\n",
    "    # 耗时任务不影响下一轮的开始，从开始时间到下一次开始时间\n",
    "    time.sleep(4)\n",
    "    sys.stdout.write('2: ' + time.strftime(\"%d.%m.%Y %H:%M:%S\") + '\\n')\n",
    "\n",
    "\n",
    "def loop():\n",
    "    while True:\n",
    "        schedule.run_pending()\n",
    "\n",
    "\n",
    "schedule.every(1).seconds.do(p1)\n",
    "schedule.every(3).seconds.do(p2)\n",
    "schedule.every(1.5).minutes.do(p1)\n",
    "t = threading.Thread(target=loop, name='send_heart')\n",
    "t.setDaemon(True)\n",
    "t.start()\n",
    "input('\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Every 2 hours do p1() (last run: [never], next run: 2020-04-12 01:00:04)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "schedule.every(2).hours.do(p1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 11.04.2020 11:02:09\n",
      "2 11.04.2020 11:02:09\n",
      "1 11.04.2020 11:02:13\n",
      "2 11.04.2020 11:02:13\n",
      "1 11.04.2020 11:02:17\n",
      "2 11.04.2020 11:02:17\n",
      "\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# -*- conding:utf-8 -*-\n",
    "import threading\n",
    "import time\n",
    "\n",
    "import schedule\n",
    "\n",
    "\n",
    "def p1():\n",
    "    print(1, time.strftime(\"%d.%m.%Y %H:%M:%S\"))\n",
    "\n",
    "\n",
    "def p2():\n",
    "    print(2, time.strftime(\"%d.%m.%Y %H:%M:%S\"))\n",
    "\n",
    "\n",
    "def loop():\n",
    "    while True:\n",
    "        schedule.run_pending()\n",
    "        # 阻塞调度\n",
    "        time.sleep(4)\n",
    "\n",
    "\n",
    "schedule.every(1).seconds.do(p1)\n",
    "schedule.every(4).seconds.do(p2)\n",
    "t = threading.Thread(target=loop, name='send_heart')\n",
    "t.setDaemon(True)\n",
    "t.start()\n",
    "input('\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# APScheduler\n",
    "\n",
    "<https://blog.csdn.net/xc_zhou/article/details/80952147>\n",
    "\n",
    "## 简介\n",
    "\n",
    "`APScheduler`的全称是`Advanced Python Scheduler`。它是一个轻量级的 Python 定时任务调度框架。**APScheduler 支持三种调度任务：固定时间间隔，固定时间点（日期），Linux 下的 Crontab 命令**。同时，它还支持异步执行、后台执行调度任务。\n",
    "\n",
    "## 安装\n",
    "\n",
    "pip install APScheduler\n",
    "\n",
    "## 使用步骤\n",
    "\n",
    "APScheduler 使用起来还算是比较简单。运行一个调度任务只需要以下三部曲：\n",
    "\n",
    "1. 新建一个 schedulers (调度器) 。\n",
    "2. 添加一个调度任务(job stores)。\n",
    "3. 运行调度任务。\n",
    "\n",
    "下面是执行每 2 秒报时的简单示例代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "code_folding": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "main: 11.04.2020 14:09:34\n",
      "task 11.04.2020 14:09:35\n",
      "task: 11.04.2020 14:09:36\n",
      "task 11.04.2020 14:09:37\n",
      "task: 11.04.2020 14:09:38\n",
      "main: 11.04.2020 14:09:39\n",
      "task 11.04.2020 14:09:39\n",
      "task: 11.04.2020 14:09:40\n",
      "task 11.04.2020 14:09:41\n",
      "task: 11.04.2020 14:09:42\n",
      "task 11.04.2020 14:09:43\n",
      "main: 11.04.2020 14:09:44task: 11.04.2020 14:09:44\n",
      "\n",
      "task 11.04.2020 14:09:45\n",
      "task: 11.04.2020 14:09:46\n",
      "task 11.04.2020 14:09:47\n",
      "task: 11.04.2020 14:09:48\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-3-c5964728d75c>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     19\u001b[0m     \u001b[1;32mwhile\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     20\u001b[0m         \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'main: {}'\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstrftime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"%d.%m.%Y %H:%M:%S\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 21\u001b[1;33m         \u001b[0mtime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msleep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "import datetime\n",
    "import time\n",
    "from apscheduler.schedulers.background import BackgroundScheduler\n",
    "\n",
    "\n",
    "def timedTask():\n",
    "    print('task: {}'.format(time.strftime(\"%d.%m.%Y %H:%M:%S\")))\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    # 创建后台执行的 schedulers\n",
    "    scheduler = BackgroundScheduler()\n",
    "    # 添加调度任务\n",
    "    # 调度方法为 timedTask，触发器选择 interval(间隔性)，间隔时长为 2 秒\n",
    "    scheduler.add_job(timedTask, 'interval', seconds=2)\n",
    "    # 启动调度任务\n",
    "    scheduler.start()\n",
    "\n",
    "    while True:\n",
    "        print('main: {}'.format(time.strftime(\"%d.%m.%Y %H:%M:%S\")))\n",
    "        time.sleep(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基础组件\n",
    "\n",
    "APScheduler 有四种组件，分别是：调度器(scheduler)，作业存储(job store)，触发器(trigger)，执行器(executor)。\n",
    "\n",
    "- schedulers（调度器）  \n",
    "它是任务调度器，属于控制器角色。它配置作业存储器和执行器可以在调度器中完成，例如添加、修改和移除作业。\n",
    "\n",
    "- triggers（触发器）  \n",
    "描述调度任务被触发的条件。不过触发器完全是无状态的。\n",
    "\n",
    "- job stores（作业存储器）  \n",
    "任务持久化仓库，默认保存任务在内存中，也可将任务保存都各种数据库中，任务中的数据序列化后保存到持久化数据库，从数据库加载后又反序列化。\n",
    "\n",
    "- executors（执行器）  \n",
    "负责处理作业的运行，它们通常通过在作业中提交指定的可调用对象到一个线程或者进城池来进行。当作业完成时，执行器将会通知调度器。\n",
    "\n",
    "---\n",
    "\n",
    "### schedulers（调度器）\n",
    "我个人觉得 APScheduler 非常好用的原因。它提供 7 种调度器，能够满足我们各种场景的需要。例如：后台执行某个操作，异步执行操作等。调度器分别是：\n",
    "\n",
    "- `BlockingScheduler` : 调度器在当前进程的主线程中运行，也就是会阻塞当前线程。\n",
    "- `BackgroundScheduler` : 调度器在后台线程中运行，不会阻塞当前线程。\n",
    "- `AsyncIOScheduler` : 结合 asyncio 模块（一个异步框架）一起使用。\n",
    "- `GeventScheduler` : 程序中使用 gevent（高性能的Python并发框架）作为IO模型，和 GeventExecutor 配合使用。\n",
    "- `TornadoScheduler` : 程序中使用 Tornado（一个web框架）的IO模型，用 ioloop.add_timeout 完成定时唤醒。\n",
    "- `TwistedSchedule`r : 配合 TwistedExecutor，用 reactor.callLater 完成定时唤醒。\n",
    "- `QtScheduler` : 你的应用是一个 Qt 应用，需使用QTimer完成定时唤醒。\n",
    "\n",
    "### triggers（触发器）\n",
    "\n",
    "APScheduler 有三种内建的 trigger:\n",
    "\n",
    "1. date 触发器\n",
    "\n",
    "date 是最基本的一种调度，作业任务只会执行一次。它表示特定的时间点触发。它的参数如下：\n",
    "\n",
    "|参数|说明  |\n",
    "|:----|:-------|\n",
    "|run_date (datetime 或 str)\t|作业的运行日期或时间\n",
    "|timezone (datetime.tzinfo 或 str)|\t指定时区\n",
    "\n",
    "date 触发器使用示例如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "from datetime import date\n",
    "from apscheduler.schedulers.background import BackgroundScheduler\n",
    "\n",
    "\n",
    "def job_func(text):\n",
    "    print(text)\n",
    "\n",
    "    \n",
    "scheduler = BackgroundScheduler()\n",
    "# 在 2020-4-11时刻运行一次 job_func 方法\n",
    "scheduler .add_job(job_func, 'date', run_date=date(2020, 4, 11), args=['text'])\n",
    "# 在 2020-4-11 14:00:00 时刻运行一次 job_func 方法\n",
    "scheduler .add_job(job_func, 'date', run_date=datetime(2020, 4, 11, 14,22, 0), args=['text'])\n",
    "# 在 2020-4-11 14:00:01 时刻运行一次 job_func 方法\n",
    "scheduler .add_job(job_func, 'date', run_date='2020-04-11 14:22:01', args=['text'])\n",
    "\n",
    "scheduler.start()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "188.6px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
